package org.ytor.core.scheduler.task;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.ytor.common.scheduler.Task;
import org.ytor.common.util.Jsons;
import org.ytor.common.util.Strs;
import org.ytor.core.CommonApi;
import org.ytor.core.sysapi.log.model.SysLog;
import org.ytor.core.sysapi.scheduler.model.SysSchedulerTask;
import org.ytor.core.sysapi.scheduler.repository.SysSchedulerTaskRepository;

import java.util.Arrays;
import java.util.Map;
import java.util.UUID;

/**
 * created by yangtong on 2025/6/17 13:34:45
 * <br/>
 * 带参数的定时任务
 */
@Slf4j
@Data
public abstract class ParameterTask implements Task {

    protected static final ScopedValue<String> LOG_ID = ScopedValue.newInstance();

    /**
     * 该任务在数据库的任务id
     */
    private String dbTaskId;

    private CommonApi commonApi;

    private SysSchedulerTaskRepository schedulerTaskRepository;

    @Autowired
    public void set(@Lazy SysSchedulerTaskRepository schedulerTaskRepository, CommonApi commonApi) {
        this.schedulerTaskRepository = schedulerTaskRepository;
        this.commonApi = commonApi;
    }

    /**
     * 获取任务参数
     */
    protected Map<String, Object> getParameters() {
        SysSchedulerTask schedulerTask = schedulerTaskRepository.queryById(dbTaskId);
        String parameter = schedulerTask.getParameter();
        return Jsons.toMap(parameter);
    }

    /**
     * 记录日志
     * @param content 日志内容（模板字符串）
     * @param args 日志内存的参数
     */
    protected final void addLog(String content, Object... args) {
        String logId = LOG_ID.get();
        commonApi.addAsyncLog(() -> new SysLog()
                .setType(5) // 5表示定时任务执行过程的日志
                .setTraceId(logId)
                .setThread(Thread.currentThread().getName())
                .setClassName(this.getClass().getName())
                .setMethodName("doTask")
                .setContent(Strs.format(content, args)));
    }

    @Override
    public void doTask() {
        long startTime = System.currentTimeMillis();
        Map<String, Object> parameters = getParameters();
        //产生该次任务唯一id，用于聚合日志
        String logId = UUID.randomUUID().toString();
        ScopedValue.runWhere(LOG_ID, logId, () -> {
            Throwable finalError = null;
            try {
                doTask(parameters);
            } catch (Throwable e) {
                log.error("任务执行失败", e);
                finalError = e;
            } finally {
                SysLog sysLog = new SysLog()
                        .setType(6) // 6表示定时任务完成日志
                        .setTraceId(LOG_ID.get())
                        .setCost(System.currentTimeMillis() - startTime)
                        .setParams(parameters.toString())
                        .setThread(Thread.currentThread().getName())
                        .setClassName(this.getClass().getName())
                        .setMethodName("doTask")
                        .setContent(finalError == null ? "执行成功" : "执行失败");

                // 报错信息
                if (finalError != null) {
                    sysLog.setErrorMsg(finalError.getMessage())
                            .setErrorStack(Arrays.toString(finalError.getStackTrace()));
                }
                commonApi.addAsyncLog(() -> sysLog);
            }
        });
    }

    abstract void doTask(Map<String, Object> parameters) throws Throwable;
}
